<!DOCTYPE HTML PUBLIC "-//ORA//DTD CD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>[Chapter 10] 10.6 Defining a Simple Property Editor</TITLE>
<META NAME="author" CONTENT="David Flanagan">
<META NAME="date" CONTENT="Thu Jul 31 15:57:51 1997">
<META NAME="form" CONTENT="html">
<META NAME="metadata" CONTENT="dublincore.0.1">
<META NAME="objecttype" CONTENT="book part">
<META NAME="otheragent" CONTENT="gmat dbtohtml">
<META NAME="publisher" CONTENT="O'Reilly &amp; Associates, Inc.">
<META NAME="source" CONTENT="SGML">
<META NAME="subject" CONTENT="Java">
<META NAME="title" CONTENT="Java in a Nutshell">
<META HTTP-EQUIV="Content-Script-Type" CONTENT="text/javascript">
</HEAD>
<body vlink="#551a8b" alink="#ff0000" text="#000000" bgcolor="#FFFFFF" link="#0000ee">

<DIV CLASS=htmlnav>
<H1><a href='index.htm'><IMG SRC="gifs/smbanner.gif"
     ALT="Java in a Nutshell" border=0></a></H1>
<table width=515 border=0 cellpadding=0 cellspacing=0>
<tr>
<td width=172 align=left valign=top><A HREF="ch10_05.htm"><IMG SRC="gifs/txtpreva.gif" ALT="Previous" border=0></A></td>
<td width=171 align=center valign=top><B><FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">Chapter 10<br>Java Beans</FONT></B></TD>
<td width=172 align=right valign=top><A HREF="ch10_07.htm"><IMG SRC="gifs/txtnexta.gif" ALT="Next" border=0></A></td>
</tr>
</table>

&nbsp;
<hr align=left width=515>
</DIV>
<DIV CLASS=sect1>
<h2 CLASS=sect1><A CLASS="TITLE" NAME="JNUT2-CH-10-SECT-6">10.6 Defining a Simple Property Editor</A></h2>

<P CLASS=para>
<A NAME="CH10.PROPERTYEDIT1"></A><A NAME="CH10.JAVABEANS.AP3"></A><A NAME="CH10.PROPERTIES.1"></A>A bean can also provide an auxiliary <tt CLASS=literal>PropertyEditor</tt> for use
by a beanbox tool.  <tt CLASS=literal>PropertyEditor</tt> is a flexible interface
that allows a bean to tell a beanbox how to display and edit
the values of certain types of properties.

<P CLASS=para>
A beanbox tool always provides simple property editors for
common property types, such as strings, numbers, fonts, and colors.
If your bean has properties of a non-standard type, you should
register a property editor for that type.  The
 
easiest way to "register" a property
editor is through a simple naming convention.  If your type is defined
by the class<I CLASS=emphasis> <tt CLASS=literal>X</tt></I>, the editor for it should be defined
in the class <tt CLASS=literal>X</tt><tt CLASS=literal>Editor</tt>.
Alternately, you can register a property editor by calling the 
<tt CLASS=literal>PropertyEditorManager.registerEditor()</tt> method,
probably from the constructor of your <tt CLASS=literal>BeanInfo</tt>
class.  If you call this method from the bean itself, the bean then
depends on the property editor class, so the editor has to be bundled
with the bean in applications.

<P CLASS=para>
In our <tt CLASS=literal>YesNoDialog</tt> example, we don't define any new
data types, but we still have two individual properties that
need custom editors.  In this case, we register the
property editors for individual properties by specifying
them in the <tt CLASS=literal>PropertyDescriptor</tt>
objects returned by the <tt CLASS=literal>getPropertyDescriptors()</tt>
method of our <tt CLASS=literal>BeanInfo</tt> class.

<P CLASS=para>
The <tt CLASS=literal>PropertyEditor</tt> interface can seem confusing at
first.  Its methods allow you to define three techniques for
displaying the value of a property and two
techniques for allowing the user to edit the value of a
property.  The value of a property can be displayed:

<P>
<UL CLASS=itemizedlist>
<li CLASS=listitem>As a string.  If you define the <tt CLASS=literal>getAsText()</tt> method,
a beanbox can convert a property to a string and display
that string to the user.

<P>
<li CLASS=listitem>As an enumerated value.  If a property can only take on a value
from a fixed set of values, you can define the <tt CLASS=literal>getTags()</tt>
method to allow a beanbox to display a dropdown menu of allowed
values for the property.

<P>
<li CLASS=listitem>In a graphical display.  If you define <tt CLASS=literal>paintValue()</tt>,
a beanbox can ask the property editor to
display the value using some natural graphical format, such
as a color swatch for colors.  You also need to
define <tt CLASS=literal>isPaintable()</tt> to specify that a graphical
format is supported.

<P>
</UL>
<P CLASS=para>
The two editing techniques are:

<P>
<UL CLASS=itemizedlist>
<li CLASS=listitem><I CLASS=emphasis>String editing</I>.  If you define the <tt CLASS=literal>setAsText()</tt>
method, a beanbox knows it can simply have the user
type a value into a text field and pass that value to
<tt CLASS=literal>setAsText()</tt>.  If your property editor defines
<tt CLASS=literal>getTags()</tt>, it should also define <tt CLASS=literal>setAsText()</tt>
so that a beanbox can set the property value using the
individual tag values.

<P>
<li CLASS=listitem><I CLASS=emphasis>Custom editing</I>.  If your property editor defines
<tt CLASS=literal>getCustomEditor()</tt>, a beanbox can call
it to obtain some kind of AWT
component that can be displayed in a dialog box and serve as
a custom editor for the property.  You also need to
define <tt CLASS=literal>supportsCustomEditor()</tt> to specify that custom editing
is supported.

<P>
</UL>
<P CLASS=para>
The <tt CLASS=literal>setValue()</tt> method of a <tt CLASS=literal>PropertyEditor</tt>
is called to specify the current value of the property.  It is this
value that should be converted to a string or graphical
representation by <tt CLASS=literal>getAsText()</tt> or
<tt CLASS=literal>paintValue()</tt>.

<P CLASS=para>
A property editor is required to maintain a list of event
listeners that are interested in changes to the value of the
property.  The <tt CLASS=literal>addPropertyChangeListener()</tt> and
<tt CLASS=literal>removePropertyChangeListener()</tt> methods are standard
event listener registration and removal methods.
When a property editor changes the value of a property,
either through <tt CLASS=literal>setAsText()</tt> or through a custom
editor, it must send a <tt CLASS=literal>PropertyChangeEvent</tt> to all
registered listeners.

<P CLASS=para>
<tt CLASS=literal>PropertyEditor</tt> defines the
<tt CLASS=literal>getJavaInitializationString()</tt>
for use by beanbox tools that generate Java code.
This method should return a
fragment of Java code that can be used to initialize a
variable to the current property value.

<P CLASS=para>
Finally, a class that implements the
<tt CLASS=literal>PropertyEditor</tt> interface must have a
no-argument constructor, so that it can be dynamically loaded
and instantiated by a beanbox.

<P CLASS=para>
Most property editors can be much simpler than this detailed
description would suggest.  In many cases, you can subclass
<tt CLASS=literal>PropertyEditorSupport</tt> instead of implementing the
<tt CLASS=literal>PropertyEditor</tt> interface directly.  This useful
class provides no-op implementations of most
<tt CLASS=literal>PropertyEditor</tt> methods.  It also implements the methods
for adding and removing event listeners.

<P CLASS=para>
A property that has an enumerated value requires a simple property
editor.  The <tt CLASS=literal>alignment</tt> property of the <tt CLASS=literal>YesNoDialog</tt> bean
is an example of this common type of property.
The property is defined as an <tt CLASS=literal>int</tt>,
but it has only three legal values, defined by the constants
<tt CLASS=literal>LEFT</tt>, <tt CLASS=literal>CENTER</tt>, and <tt CLASS=literal>RIGHT</tt>.  By default,
a beanbox only knows that the property is an <tt CLASS=literal>int</tt>,
so it displays the property as a number and allows the
user to enter any integer as a property value.  Instead, we
would like the beanbox to display one
of the strings "left," "center," or "right" as the value,
and allow the user to choose from these values when
setting the property.  This can be
done with the <tt CLASS=literal>getTags()</tt> and <tt CLASS=literal>setAsText()</tt>
methods of a property editor, as shown in
<A HREF="ch10_06.htm#JNUT2-CH-10-EX-6">Example 10.6</A>.

<P CLASS=para>
This example creates the <tt CLASS=literal>YesNoDialogAlignmentEditor</tt>
class, which is registered as a <tt CLASS=literal>PropertyEditor</tt> for the
<tt CLASS=literal>alignment</tt> property by the
<tt CLASS=literal>YesNoDialogBeanInfo</tt> class shown in
<A HREF="ch10_05.htm#JNUT2-CH-10-EX-5">Example 10.5</A> . 
The property editor subclasses <tt CLASS=literal>PropertyEditorSupport</tt>,
so it is relatively short.  Notice that it passes
<tt CLASS=literal>Integer</tt> objects in the calls to <tt CLASS=literal>setValue()</tt> that are
made from the <tt CLASS=literal>setAsText()</tt> method.  You need to use
wrapper objects for any primitive-type properties.  The use
of the <tt CLASS=literal>Integer</tt> class is also apparent in the definition of
<tt CLASS=literal>getJavaInitializationString()</tt>.
The <tt CLASS=literal>setValue()</tt> method of
<tt CLASS=literal>ProperyEditorSupport</tt> handles notifying
registered <tt CLASS=literal>PropertyChangeListener</tt> objects about changes
in the value of the property, so this
simple property editor does not need to be aware of the
existence of such listeners.

<DIV CLASS=example>
<h4 CLASS=example><A CLASS="TITLE" NAME="JNUT2-CH-10-EX-6">Example 10.6: The YesNoDialogAlignmentEditor Class</A></h4>

<DIV CLASS=screen>
<P>
<PRE>
package oreilly.beans.yesno;
import java.beans.*;
import java.awt.*;
public class YesNoDialogAlignmentEditor extends PropertyEditorSupport {
  // These two methods allow the property to be edited in a dropdown list.
  // Return the list of value names for the enumerated type.
  public String[] getTags() {
    return new String[] { "left", "center", "right" };
  }
  // Convert each of those value names into the actual value.
  public void setAsText(String s) {
    if (s.equals("left")) setValue(new Integer(YesNoDialog.LEFT));
    else if (s.equals("center")) setValue(new Integer(YesNoDialog.CENTER));
    else if (s.equals("right")) setValue(new Integer(YesNoDialog.RIGHT));
    else throw new IllegalArgumentException(s);
  }
  // This is an important method for code generation.
  public String getJavaInitializationString() {
    switch(((Number)getValue()).intValue()) {
    default:
    case YesNoDialog.LEFT:   return "oreilly.beans.yesno.YesNoDialog.LEFT";
    case YesNoDialog.CENTER: return "oreilly.beans.yesno.YesNoDialog.CENTER";
    case YesNoDialog.RIGHT:  return "oreilly.beans.yesno.YesNoDialog.RIGHT";
    }
  }
}
</PRE>
</DIV>

</DIV>

</DIV>


<DIV CLASS=htmlnav>

<P>
<HR align=left width=515>
<table width=515 border=0 cellpadding=0 cellspacing=0>
<tr>
<td width=172 align=left valign=top><A HREF="ch10_05.htm"><IMG SRC="gifs/txtpreva.gif" ALT="Previous" border=0></A></td>
<td width=171 align=center valign=top><a href="index.htm"><img src='gifs/txthome.gif' border=0 alt='Home'></a></td>
<td width=172 align=right valign=top><A HREF="ch10_07.htm"><IMG SRC="gifs/txtnexta.gif" ALT="Next" border=0></A></td>
</tr>
<tr>
<td width=172 align=left valign=top>Specifying Bean Information</td>
<td width=171 align=center valign=top><a href="index/idx_0.htm"><img src='gifs/index.gif' alt='Book Index' border=0></a></td>
<td width=172 align=right valign=top>Defining a Complex Property Editor</td>
</tr>
</table>
<hr align=left width=515>

<IMG SRC="gifs/smnavbar.gif" USEMAP="#map" BORDER=0> 
<MAP NAME="map"> 
<AREA SHAPE=RECT COORDS="0,0,108,15" HREF="../javanut/index.htm"
alt="Java in a Nutshell"> 
<AREA SHAPE=RECT COORDS="109,0,200,15" HREF="../langref/index.htm" 
alt="Java Language Reference"> 
<AREA SHAPE=RECT COORDS="203,0,290,15" HREF="../awt/index.htm" 
alt="Java AWT"> 
<AREA SHAPE=RECT COORDS="291,0,419,15" HREF="../fclass/index.htm" 
alt="Java Fundamental Classes"> 
<AREA SHAPE=RECT COORDS="421,0,514,15" HREF="../exp/index.htm" 
alt="Exploring Java"> 
</MAP>
</DIV>

</BODY>
</HTML>
